/*
 * Copyright (C) 2015 soud
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef AST_H
#define AST_H

#include <stdint.h>
#include <limits.h>

#include "lexer.h"

typedef enum {
        INT,
        I8,
        I16,
        I32,
        I64,
        U8,
        U16,
        U32,
        U64,
        STR,
        CHAR,
        BOOL,
        FLOAT,
        F32,
        F64,
        NONE,
        UNKNOWN
} ast_type_t;

typedef enum {
        ASSOC_LEFT,
        ASSOC_RIGHT,
        ASSOC_NONE
} ast_assoc_t;

typedef struct {
        tokentype symbol;
        int precedence;
        ast_assoc_t assoc;
        bool unary;
} ast_op_t;

struct ast_node;
struct ast_node_list;

/* TODO: number types */
typedef struct {
        float value;
} ast_number_t;

typedef struct {
        char *name;
        ast_type_t data_type;
        bool mutable;
        struct ast_node *value;
} ast_var_t;

typedef struct {
        char *name;
        struct ast_node_list *args;
        ast_type_t data_type;
} ast_proto_t;

typedef struct {
        struct ast_node *prototype;
        struct ast_node_list *body;
} ast_fn_t;

typedef struct {
        char *name;
        struct ast_node_list *args;
} ast_call_t;

typedef struct {
        struct ast_node *condition;
        struct ast_node_list *true_body;
        struct ast_node_list *false_body;
} ast_if_t;

typedef struct {
        ast_op_t operator;

        struct ast_node *lhs;
        struct ast_node *rhs;
} ast_bin_expr_t;

typedef struct ast_node {
        enum {
                TYPE_NUMBER,
                TYPE_VAR,
                TYPE_PROTO,
                TYPE_FN,
                TYPE_CALL,
                TYPE_IF,
                TYPE_BIN_EXPR
        } type;

        union {
                ast_number_t number;
                ast_var_t var;
                ast_proto_t prototype;
                ast_fn_t fn;
                ast_call_t call;
                ast_if_t if_expr;
                ast_bin_expr_t bin_expr;
        };
} ast_node_t;

typedef struct ast_node_list {
        ast_node_t *node;
        struct ast_node_list *next;
} ast_node_list_t;

ast_node_t *create_number(float value);
ast_node_t *create_var(char *name, ast_type_t data_type, bool mutable, ast_node_t *value);
ast_node_t *create_fn_proto(char *name, ast_node_list_t *args, ast_type_t data_type);
ast_node_t *create_fn(ast_node_t *prototype, ast_node_list_t *body);
ast_node_t *create_call(char *name, ast_node_list_t *args);
ast_node_t *create_if(ast_node_t *condition, ast_node_list_t *true_body,
                      ast_node_list_t *false_body);
ast_node_t *create_bin_expr(ast_op_t operator, ast_node_t *lhs, ast_node_t *rhs);
ast_node_list_t *create_node_list(void);
void swap_lists(ast_node_list_t *a, ast_node_list_t *b);
void destroy_ast(ast_node_list_t *nl);
void dump_node_list(ast_node_list_t *nl);

#endif /* !AST_H */
